import { IPageResponse } from "../../../common/CommonType";
import { ValidationError } from "../../../utils/errors";
import appDataSource from "../../../db";
import SysRoleEntity from "../role/Entity";
import SysMenuEntity from "./Entity";
import { generateRoutes } from "./utils/menuTool";
import SysUserEntity from "../user/Entity";
import SysMenuMetaEntity from "../menuMeta/Entity";
import SysMenuPermissionEntity from "../menuPermission/Entity";
import { In } from "typeorm";

export class SysMenuService {
  /**
   * 添加数据
   */
  public static async add(data: SysMenuEntity): Promise<true> {
    // 1. 转换类型
    data = SysMenuEntity.transform(data);
    // 2. 数据验证
    const errors = await data.validateThis();
    if (errors.length > 0) {
      throw new ValidationError(errors[0]);
    }

    // 3. 当meta有不为空时验证meta并保存
    if (data.meta && Object.keys(data.meta).length > 0) {
      const meta = SysMenuMetaEntity.transform(data.meta);
      const metaErrors = await meta.validateThis();
      if (metaErrors.length > 0) {
        throw new ValidationError(metaErrors[0]);
      }
      data.meta = meta;
      const metaRes = appDataSource.getRepository(SysMenuMetaEntity);
      await metaRes.save(meta);
    }

    // 4. 当 permission 不为空时验证并保存
    if (data.permission && data.permission.length > 0) {
      const permissionRep = appDataSource.getRepository(SysMenuPermissionEntity);
      const permissionData = await permissionRep.find({
        where: {
          id: In(data.permission),
        },
      });
      data.permission = permissionData;
    }

    const rep = appDataSource.getRepository(SysMenuEntity);
    await rep.save(data);
    return true;
  }

  /**
   * 分页获取数据
   */
  public static async findByPage(current: number, size: number, where?: any): Promise<IPageResponse> {
    const rep = appDataSource.getRepository(SysMenuEntity);
    const [list, total] = await rep.findAndCount({
      skip: size * (current - 1),
      take: size,
      where,
    });

    return {
      total,
      list,
    };
  }

  /**
   * 无分页
   */
  public static async findByList(where?: any) {
    const rep = appDataSource.getRepository(SysMenuEntity);
    return rep.find({
      where,
    });
  }

  /**
   * 通过id获取数据
   */
  public static async findById(id: string) {
    const rep = appDataSource.getRepository(SysMenuEntity);
    const data = await rep.findOne({
      where: { id: +id },
      relations: {
        meta: true,
        permission: true,
      },
    });
    if (data) {
      data.permissionLabels = data.permission.map((item) => item.label);
      data.permission = data.permission.map((item) => item.id) as any;

      const parentMenu = await rep.findOne({
        where: {
          id: data.parentId,
        },
      });

      data.parentName = parentMenu?.name || "无";
    }
    return data;
  }

  /**
   * 修改数据
   */
  public static async update(data: any) {
    const rep = appDataSource.getRepository(SysMenuEntity);
    const result = await rep.update(data.id, data);
    return result.raw;
  }

  /**
   * 删除数据
   */
  public static async delete(id: string) {
    const rep = appDataSource.getRepository(SysMenuEntity);
    const result = await rep.softDelete({ id: +id });
    return result.raw;
  }

  /**
   * 获取前端路由
   * @param type 0 构建前端路由，1直接返回菜单的树形结构
   */
  public static async getFrontRoutes(userInfo: SysUserEntity, type: number = 0) {
    const userRep = appDataSource.getRepository(SysUserEntity);
    const roleRep = appDataSource.getRepository(SysRoleEntity);
    const menuRep = appDataSource.getRepository(SysMenuEntity);

    // 1.找到用户的角色
    const user = await userRep.findOne({
      where: { id: userInfo.id },
      relations: { roles: true },
    });
    if (!user || user.roles.length === 0) {
      return [];
    }

    // 仅支持单角色
    // 2.找出角色的菜单
    const role = await roleRep.findOne({
      where: {
        id: (user.roles[0] as SysRoleEntity).id,
      },
      relations: ["menus", "menus.permission", "menus.meta"],
    });

    if (!role) {
      return [];
    }
    let menus: SysMenuEntity[];

    if (role.roleKey === "admin") {
      menus = await menuRep.find({
        where: { status: 1 },
        relations: ["meta", "permission"],
      });
    } else {
      menus = role.menus as SysMenuEntity[];
    }
    if (role?.rolePermissionList) {
      const rolePermissionList = JSON.parse(role.rolePermissionList);
      menus.forEach((item) => {
        item.meta.rolePermissionList = rolePermissionList[item.id];
      });
    }
    // 构建菜单
    return generateRoutes(menus, type);
  }
}
